import os
import numpy as np
from cuda import cudart
import tensorrt as trt


class DecoderCalibrator(trt.IInt8EntropyCalibrator2):

    def __init__(self, cacheFile, num_calib):
        trt.IInt8EntropyCalibrator2.__init__(self)

        self.data_dir = "datas"
        self.cacheFile = cacheFile
        self.batch_size = 1
        self.num_calib = num_calib
        self.count = 0

        self.buffer_sizes = [np.zeros([1, 4, 32, 48], dtype=np.float32).nbytes]
        self.buffers = []
        self.buffers.append(cudart.cudaMalloc(self.buffer_sizes[0])[1])

    def __del__(self):
        cudart.cudaFree(self.buffers[0])

    def get_batch_size(self):  # do NOT change name
        return self.batch_size

    def get_batch(self, nameList=None, inputNodeName=None):  # do NOT change name
        if self.count >= self.num_calib:
            return None

        batchData = np.load(os.path.join(self.data_dir, "batch{}.npy".format(self.count)))
        cudart.cudaMemcpy(self.buffers[0], batchData.ctypes.data, batchData.nbytes, cudart.cudaMemcpyKind.cudaMemcpyHostToDevice)
        self.count += 1
        return self.buffers

    def read_calibration_cache(self):  # do NOT change name
        if os.path.exists(self.cacheFile):
            print("Succeed finding int8 cahce: %s" % (self.cacheFile))
            with open(self.cacheFile, "rb") as f:
                cache = f.read()
                return cache
        else:
            print("Failed finding int8 cache!")
            return None

    def write_calibration_cache(self, cache):  # do NOT change name
        with open(self.cacheFile, "wb") as f:
            f.write(cache)
        print("Succeed saving int8 cache: %s" % (self.cacheFile))
